package csc.ex.bs.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

public abstract class GenericDaoImpl<T extends Serializable, I extends Serializable>  implements GenericDao<T, I>{

	private Class<T> clazz;
	
    @Autowired
    private SessionFactory sessionFactory;
    
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    protected SessionFactory getSessionFactory() {
        if (sessionFactory == null)
            throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
        return sessionFactory;
    }
    
    public Session getSession(){
    	return getSessionFactory().getCurrentSession();
    }
    
    public Class<T> getClazz() {
		return clazz;
	}
	public void setClazz(Class<T> clazz) {
		this.clazz = clazz;
	}
	
    @SuppressWarnings("unchecked")
	public GenericDaoImpl() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
    
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	@Override
	public T find(I id) {
		return (T) getSession().get(getClazz(), id);
	}

	@Transactional
	@Override
	public void save(T obj) {
		getSession().saveOrUpdate(obj);
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	@Override
	public List<T> findAll() {
		return getSession().createCriteria(getClazz()).list();
	}

	@Transactional(readOnly = true)
	@Override
	public Integer count() {
		return ((Number) getSession().createCriteria(getClazz()).setProjection(Projections.rowCount()).uniqueResult()).intValue();
	}

	@Transactional
	@Override
	public void delete(T obj) {
		getSession().delete(obj);
	}
	
	
	
	
	
	

}
